package cn.edu.xust.communication.server;

import cn.edu.xust.communication.model.Result;
import cn.edu.xust.communication.server.cache.ChannelMap;
import cn.edu.xust.communication.server.handler.NettyServerDefaultHandler;
import cn.edu.xust.communication.util.HexConverter;
import cn.edu.xust.communication.util.StringUtils;
import cn.edu.xust.configuration.exception.Default200Exception;
import cn.edu.xust.configuration.exception.ErrorConstant;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;

import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


@Slf4j
public class CommonOp {


    private static Lock lock = new ReentrantLock();

    /**
     * 执行设备控制，向设备发送命令
     *
     * @param deviceIp 设备ID
     * @param cmd      下发的命令
     */
    public static Result writeCommand(String deviceIp, String cmd, String uuid) throws Default200Exception {
        //获取通道
        ChannelHandlerContext ctx = ChannelMap.getDeviceFromMap(deviceIp);
        if (Objects.isNull(deviceIp) || Objects.isNull(ctx)) {
            log.warn("通道中没有找到该ip,抛出异常:deviceIp:{}", deviceIp);
            throw new Default200Exception(ErrorConstant.no_ip);
        }
        if (Objects.isNull(cmd)) {
            log.info("指令为空");
            throw new Default200Exception(ErrorConstant.gen_cmd_null);
        }
        //发送查询数据
        return writeMessage2Client(ctx, cmd, uuid);
    }

    /**
     * 向客户端写数据,并且同步等待客户端返回消息
     *
     * @param ctx    服务器和设备建立的通道
     * @param hexMsg 命令信息
     * @param uuid   消息的唯一编号
     */


    public static Result writeMessage2Client(ChannelHandlerContext ctx, String hexMsg, String uuid) throws Default200Exception {
        Channel channel = ctx.channel();


        boolean isLocked;
        try {
            isLocked = lock.tryLock(5, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            log.info("等待锁:出错");
            log.info(String.valueOf(e));
            throw new Default200Exception(ErrorConstant.other_query);
        }
        if (isLocked) {
            try {
                log.info("拿到锁了");
                if (channel.isOpen()) {
                    log.info("通道是打开的");
                    //设置同步
                    CountDownLatch latch = new CountDownLatch(1);
                    ChannelHandler channelHandler = ctx.handler();
                    if (channelHandler instanceof NettyServerDefaultHandler) {
                        ((NettyServerDefaultHandler) channelHandler).resetSync(latch, 1);
                        ((NettyServerDefaultHandler) channelHandler).setUnidId(uuid);
                        ByteBuf byteBuf = Unpooled.buffer();
                        byteBuf.writeBytes(HexConverter.hexString2ByteArray(hexMsg));
                        //发送消息并添加监听，监听发送的结果，打印结果日志
                        channel.writeAndFlush(byteBuf).addListener((ChannelFutureListener) channelFuture -> {
                            String remoteAddress = channel.remoteAddress().toString();
                            if (channelFuture.isSuccess()) {
                                log.info("成功发送给{}，hex:{},翻译：{}", remoteAddress, hexMsg, StringUtils.fromHexString(hexMsg));
                            } else {
                                log.info("失败发送给{},{}", remoteAddress, hexMsg);
                            }
                            if (byteBuf.refCnt() > 0) {
                                byteBuf.release();
                            }
                        });
                        //3秒内收到消息就执行下面操作
                        if (latch.await(3, TimeUnit.SECONDS)) {
                            Result result = ((NettyServerDefaultHandler) channelHandler).getResult();
                            result.setCode(1);
                            //查水表时，水表会单独发次条00，不含数据，无意义，所以这个不解析，也就不返回,非00的数据才返回
                            if (!result.getMessage().equals("00")) {
                                return result;
                            }
                        }
                        //超过3秒 返回超时
                        log.error("指令发送后，已超过3秒无响应");
                    }
                    throw new Default200Exception(ErrorConstant.timeout3);
                } else {
                    throw new Default200Exception(ErrorConstant.client_closed);
                }
            } catch (Default200Exception e) {
                throw e;
            } catch (Exception e) {
                log.warn(String.valueOf(e));
                throw new Default200Exception(ErrorConstant.internal_err);
            } finally {
                log.info("释放锁了");
                lock.unlock();
            }
        } else {
            // 未获取到锁的处理逻辑
            log.info("等待锁:超时");
            throw new Default200Exception(ErrorConstant.other_query);
        }
    }
}
